home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1998 July / EnigmA AMIGA RUN 29 (1998)(G.R. Edizioni)(IT)[!][issue 1998-07 & 08].iso / recent / graburl.lha / GrabURL / rexx / GrabURL.rexx
OS/2 REXX Batch file  |  1998-01-07  |  24KB  |  705 lines

  1. /******************************************************************************
  2. *
  3. * $VER: GrabURL 1.06 (4.8.97) (c) 1996-97 Serge Emond
  4. *
  5. *******************************************************************************
  6. *
  7. * Url Types:
  8. *   F   Failed.
  9. *   Q   Queued
  10. *   R   Received
  11. *   X   Error.
  12. *   U   Unused/Unknown
  13. *
  14. ******************************************************************************/
  15.  
  16. options results
  17. options failat 100
  18. signal on break_c
  19. signal on halt
  20. signal on ioerr
  21.  
  22. PARSE ARG Arguments
  23. call Main
  24. call DoFail 0
  25.  
  26.  
  27. /********************************************************* Default Settings **/
  28.  
  29. DoDefaults:
  30.  
  31.   /* Boolean are always set by ReadArgs.. no defaults! */
  32.  
  33.   opts.Url.Count =      0                           /* Don't grab url */
  34.   opts.Depth =         -1                           /* Grab the world! */
  35.   opts.InFile =         ''                          /* Don't read files */
  36.   opts.MaxSize =        0                           /* No limit */
  37.   opts.MinSpaceLeft =   0                           /* No Checking */
  38.   opts.Pattern =        ''                          /* No Pattern Matching */
  39.   opts.SaveRoot =       'Work:Urls/'                /* Where to put files */
  40.   opts.WorkFile =       ''                          /* No WorkFile */
  41.   opts.Delay =          0   /* seconds */           /* Delay between grabs */
  42.   opts.MaxTime =        0   /* minutes */           /* Max. time to download */
  43.   opts.MaxCount =       0                           /* Max. # of file to grab */
  44.   opts.MaxBytes =       0                           /* Max. # of bytes to grab */
  45.  
  46.   /* Defaults not configurable on command-line */
  47.   
  48.   def.KeepReceived =    1   /* 1 = Keep Recd in list, 0 = Remove Them */
  49.   def.KeepFailed =      1   /* 1 = Keep Failed in list, 0 = Remove Them */
  50.   def.KeepUnused =      1   /* 1 = Keep Unused in list */
  51.   def.FollowMoved =     1   /* 1 = Grab new destination given by the server */
  52.   def.FollowTMoved =    1   /* 1 = Same as def.FollowMoved but when a */
  53.                             /* Temporary Move is issued */
  54.   def.Secure =          1   /* 1 = Save WorkFile each time it is modified */
  55.                             /* 0 = Save on exit only */
  56.   def.Accept =      '*/*'   /* We accept all types of files */
  57.   def.EMail =           ''  /* We are anonymous.. */
  58.   def.TimeZone =       300  /* Minutes to ADD to localtime to get GMT */
  59.   def.WriteBufSize = 16*1024 /* Write Buffer Size */
  60.   def.Translate = '~:[]()'  /* Characters to be translated to "_" when saving
  61.                                to disk */
  62.   def.TranslateTo = copies("_", length(def.Translate))
  63.                             /* Characters to translate to.. */
  64.  
  65.   def.TouchOldDirs =    1   /* 1 = Reset date of old directories */
  66.   
  67.   def.TempFile =    't:GrabURL.'UID /* Temporary file to use when parsing */
  68.  
  69.   def.ParsePattern = '(FTP|HTTP)://#?'  /* Just add ftp & http in the list */
  70.   
  71.   def.PasswordFile =    ''  /* File containing authentication infos */
  72.   
  73.   /* Where to find external programs */
  74.   def.Path       = ''
  75.   def.ScanHTML  = def.Path'ScanHTML'
  76.   def.GrabHTTP   = 'run <>nil: 'def.Path'GrabHTTP'
  77.   def.UrlManager = 'run <>nil: 'def.Path'UrlManager'
  78.   
  79.   /* Output information */
  80.   def.Output        = 'CONSOLE:'
  81.   def.Progress      = 1         /* 1 = Display progress in window */
  82.   def.ExitOnClose   = 0         /* 1 = Abort everything if CloseGadget
  83.                                    event.  0 = Skip current file  */
  84.  
  85.   /* ARexx Port Names */
  86.   um    = 'UM'UID
  87.   gh    = 'GH'UID
  88.   
  89. return 0
  90.  
  91. /**************************************************************** DoDefines **/
  92.  
  93. DoDefines:
  94.     UID = pragma('i')   /* Unique ID */
  95.     
  96.     if ~show('L', "rexxsupport.library") then
  97.         call AddLib("rexxsupport.library", 0, -30)
  98.     if ~show('L', "rexxdossupport.library") then
  99.         call AddLib("rexxdossupport.library", 0, -30, 0)
  100.     
  101.     opts = "Help/S,Url=U/M,Delay/N,Depth=D/N,HeaderOnly=HO/S,"
  102.     opts = opts"IfModified=IM/S,InFile=IF/K,MaxBytes=MB/N,MaxCount=MC/N,"
  103.     opts = opts"MaxSize=MS/N,MaxTime=MT/N,MinSpaceLeft=MSL/N,"
  104.     opts = opts"NoBG/S,NoDirs=ND/S,NoHRef/S,NoSrc/S,NotExists=NE/S,"
  105.     opts = opts"Pattern=P/K,Query=Q/S,Recursive=R/S,Retry/S,"
  106.     opts = opts"SaveHeaders=SH/S,SaveRoot=SR/K,WorkFile=WF/K"
  107.     
  108.     LF = '0a'x
  109.     
  110. return 0
  111.  
  112. /** Main *********************************************************************/
  113.  
  114. Main:
  115.     call DoDefines
  116.     call DoDefaults
  117.     
  118.     if ~open('l', def.Output, 'W') then do
  119.         say 'Can''t open output display'
  120.         exit(10)
  121.     end
  122.  
  123.     if Arguments = '?' then do
  124.         call Log(opts)
  125.         call DoFail 0
  126.     end
  127.  
  128.     if strip(Arguments) = '' then do
  129.         call Log("Nothing to do!")
  130.         call DoFail 10
  131.     end
  132.  
  133.     if ~ReadArgs(Arguments, opts, "opts.") then
  134.         call DoFail(10, 'Error: 'Fault(RC))
  135.     
  136.     if opts.Help then call DisplayHelp
  137.     
  138.     /* Do we have something to do? */
  139.     if (opts.Url.Count = 0) & (opts.InFile = '') & (opts.WorkFile = '') then
  140.         DoFail 0
  141.     
  142.     call DoInit
  143.     call ReadRealms
  144.  
  145.     /* ScanHTML really likes stack.. */
  146.     oldstack = pragma('s',16384)
  147.     if oldstack>16384 then call pragma('s',oldstack)
  148.     drop oldstack
  149.  
  150.     call OpenPorts
  151.     
  152.     call AddUrls
  153.         
  154.     call cmd(um, 'GetInMem')
  155.     
  156.     call TheLoop
  157.     
  158.     if ~def.KeepReceived then call cmd(um, 'KillType R')
  159.     if ~def.KeepFailed then call cmd(um, 'KillType F')
  160.     call SaveWorkFile
  161.     
  162. call DoFail 0
  163.  
  164. /** Log **********************************************************************/
  165.  
  166. Log:
  167.     PARSE ARG log_text, log_nolf
  168.     
  169.     if log_nolf=1 then call writech('l', log_text)
  170.     else call writeln('l', log_text)
  171.     
  172.     drop log_text log_nolf
  173. return 0
  174.  
  175. /** DoFail********************************************************************/
  176. break_c:
  177.     say '***BREAK'
  178.     call DoFail 10
  179. DoFail:
  180.     PARSE ARG fail.rc, fail.msg
  181.     
  182.     if fail.rc = '' then fail.rc = 0
  183.     if text_message~='' & fail.rc~=0 then call Log(fail.msg)
  184.     
  185.     if show('P', gh) then call cmd(gh, 'Quit')
  186.     if show('P', um) then call cmd(um, 'Quit')
  187.     
  188.     call close('l')
  189.     
  190. exit fail.rc
  191.  
  192. /** Display Help *************************************************************/
  193.  
  194. DisplayHelp:
  195.     call Log "Arguments (Abbrev) <arg>"
  196.     call Log "    <#> -> number"
  197.     call Log "    <s> -> string"
  198.     call Log
  199.     call Log " URL (U) <s>         Url to grab (can have multiple arguments)"
  200.     call Log " InFile (IF) <s>     Input file containing one url/line to grab"
  201.     call Log " WorkFile (WF) <s>   File to load/save urls to.  (Keeping flags)"
  202.     call Log ""
  203.     call Log " Depth (D) <#>       Level of recursion (Default: grab indefinitely)"
  204.     call Log " IfModified (IM)     Grab only files modified since last grab"
  205.     call Log " MaxCount (MC) <#>   Maximal number of file to grab"
  206.     call Log " MaxSize (MS) <#>    Maximal size a file can have in order to grab it"
  207.     call Log " MaxTime (MT) <#>    Maximal time to download in minutes"
  208.     call Log " MinSpaceLeft (MSL) <#>  Minimal space to leave on disk when grabbing"
  209.     call Log " NoBG                Don't get background images"
  210.     call Log " NoHRef              Don't get referenced files"
  211.     call Log " NoSrc               Don't get 'SRC' urls"
  212.     call Log " NotExists (NE)      Grab only if the file does not already exists on disk"
  213.     call Log " Pattern (P) <s>     AmigaDOS pattern telling which URLs to grab"
  214.     call Log " Query (Q)           Allow '?' in urls"
  215.     call Log " Recursive (R)       Collect files recursively"
  216.     call Log " Retry               Retry files that failed"
  217.     call Log ""
  218.     call Log " Delay <#>           Time to wait between each grab (seconds)"
  219.     call Log " HeaderOnly (HO)     Grab headers, not the files"
  220.     call Log " NoDir (ND)          Don't create dirs - put the file in current directory"
  221.     call Log " SaveHeaders (SH)    Save the header of each file (.HDR)"
  222.     call Log " SaveRoot (SR) <s>   Directory where to put files"
  223.     call Log ""
  224.     call Log "Please see docs for more infos."
  225.     call DoFail 0
  226.  
  227. /** cmd **********************************************************************/
  228.  
  229. /* Send a string to an ARexx port */
  230.  
  231. cmd:
  232.     PARSE ARG port, commd
  233.     
  234.     address value port
  235.     
  236.     commd
  237.     
  238.     drop port string
  239. return RC
  240.  
  241. /** DoInit - Initialize Vars *************************************************/
  242.  
  243. DoInit:
  244.     g.cnt = 0                       /* # of url we are grabbing */
  245.     g.bytes = 0                     /* # of bytes we received */
  246.     opts.TDelay = 50 * opts.Delay   /* Transform in ticks */
  247.     opts.MaxTimeS = opts.MaxTime*60 /* Transform in seconds */
  248.     call time('r')                  /* Reset the time to 0 */
  249.  
  250. return 0
  251.  
  252. /** OpenPorts ****************************************************************/
  253.  
  254. OpenPorts:
  255.     
  256.     /* Port already in use...? */
  257.     if show('P', gh) then call DoFail(10, 'Port already in use')
  258.     /* Port already in use...? */
  259.     if show('P', um) then call DoFail(10, 'Port already in use')
  260.  
  261.     /* Start GrabHTTP */
  262.     OP.cmd = def.GrabHTTP' PORT 'gh' ACCEPT 'def.Accept' WBuf 'def.WriteBufSize
  263.     address command OP.cmd
  264.     if RC ~= 0 then call DoFail(10, 'Can''t start GrabHTTP')
  265.     
  266.     OP.i=0; do forever
  267.         if show('P', gh) then break
  268.         OP.i = OP.i + 1
  269.         if OP.i = 10 then call DoFail(10, 'Can''t find GrabHTTP''s port')
  270.         call Delay(50)      /* Wait 0.2 secs (10*20/50) */
  271.     end
  272.     
  273.     /* Add '/' to SaveRoot path */
  274.     OP.test = opts.SaveRoot ~= ''
  275.     OP.test = OP.test & right(opts.SaveRoot,1) ~= ':'
  276.     OP.test = OP.test & right(opts.SaveRoot,1) ~= '/'
  277.     if OP.test then opts.SaveRoot = opts.SaveRoot'/'
  278.     drop OP.test
  279.         
  280.     /* CD to SaveRoot dir */
  281.     if cmd(gh, 'SetDir "'opts.SaveRoot'"') ~= 0 then
  282.         call DoFail(10, 'Error cd saveroot directory')
  283.     
  284.     /* Set other defaults */
  285.     call cmd(gh, 'SetMinSpaceLeft 'opts.MinSPaceLeft)
  286.     call cmd(gh, 'SetEMail 'def.EMail)
  287.     if cmd(gh, 'SetTimeZone m 'def.TimeZone) ~= 0 then
  288.         call DoFail(10, 'Error setting TimeZone')
  289.     
  290.     /* Start UrlManager */
  291.     OP.cmd = def.UrlManager || ' PORT ' || um
  292.     address command OP.cmd
  293.     if RC ~= 0 then call DoFail(10, 'Can''t start UrlManager')
  294.     
  295.     OP.i=0; do forever
  296.         if show('P', um) then break
  297.         OP.i = OP.i + 1
  298.         if OP.i = 10 then call DoFail(10, 'Can''t find UrlManager''s port')
  299.         call Delay(20)      /* Wait 0.2 secs (10*20/50) */
  300.     end
  301.     
  302.     drop OP.i OP.cmd
  303. return 0
  304.  
  305. /** AddUrls ******************************************************************/
  306.  
  307. /* Priority: CLI urls prevails on InFile, InFile on WorkFile */
  308.  
  309. AddUrls:
  310.     /* Add Urls */
  311.     if opts.Url.count ~= 0 then do i = 0 to opts.Url.count-1
  312.         
  313.         /* Simple HTTP:// checking */
  314.         if left(upper(opts.Url.i),7) ~= 'HTTP://' then iterate
  315.         
  316.         thecmd = 'AddUrl TYPE Q URL "'opts.Url.i'" DEPTH '
  317.         if opts.Recursive then thecmd = thecmd || opts.Depth
  318.         else thecmd = thecmd || '0'
  319.         
  320.         if cmd(um, thecmd) = 2 then call DoFail(10, "Error adding url")
  321.     end
  322.     drop i
  323.     
  324.     /* Add InFile */
  325.     if opts.InFile ~='' then do
  326.         thecmd = 'ReadFile FILE "'opts.InFile'" TYPE Q DEPTH '
  327.         if opts.Recursive then thecmd = thecmd || opts.Depth
  328.         else thecmd = thecmd || '0'
  329.         
  330.         if cmd(um, thecmd) ~= 0 then call DoFail(10, "Error adding InFile")
  331.     end
  332.     drop thecmd
  333.     
  334.     /* Get WorkFile */
  335.     if (opts.WorkFile ~= '') & exists(opts.WorkFile) then
  336.         call cmd(um, 'LoadFile "'opts.WorkFile'"')
  337. return 0
  338.  
  339. /** SaveWorkFile *************************************************************/
  340.  
  341. SecureWorkFile:
  342.  
  343.     /* Don't save if not secure */
  344.     if ~def.Secure then return 0
  345.  
  346. SaveWorkFile:
  347.  
  348.     /* Don't save if no workfile! 8) */
  349.     if opts.WorkFile = '' then return 0
  350.     
  351.     if cmd(um, 'SaveFile FILE "'opts.WorkFile'" FULL') ~= 0 then
  352.         call DoFail(10, "Error: Can't save workfile!?")
  353. return 0
  354.  
  355. /** Realm Stuff **************************************************************/
  356.  
  357. ReadRealms:
  358.     if def.PasswordFile='' then do
  359.         authtot=0
  360.         return 0
  361.     end
  362.     if ~open('r',def.PasswordFile,'r') then
  363.         call DoFail(20, 'Error openning password file')
  364.     rri=0
  365.     do while ~eof('r')
  366.         line = readln('r')
  367.         if line='' then iterate
  368.         if left(line,1)=';' then iterate
  369.         rri=rri+1
  370.         parse var line authr.rri':'authu.rri
  371.     end
  372.     close('r')
  373.     authtot = rri
  374.     drop rri
  375. return 0
  376.  
  377. GetRealm:
  378.     PARSE ARG gr.rlm
  379.     do gri=1 to authtot
  380.         if gr.rlm = authr.gri then return authu.gri
  381.     end
  382. return ''
  383.  
  384. /** TheLoop ******************************************************************/
  385.  
  386. TheLoop:
  387.     call TheLoop2 'Q'
  388.     if opts.Retry then
  389.         call TheLoop2 'F'
  390. return 0
  391.  
  392. TheLoop2:
  393. parse arg tl.type
  394.     /* First we do 'Q'ueued urls */
  395.     j = 1; gu.lmoved = 0
  396.     do forever
  397.         if gu.lmoved = 0 then do
  398.             call cmd(um, 'Search 'j' type 'tl.type' pattern "HTTP://#?"')
  399.             i = umres
  400.  
  401.             if i=0 then break       /* No more url */
  402.  
  403.             call cmd(um, 'GetInMem');l.t=umres
  404.             call cmd(um, 'CountType "Q"');l.q=umres
  405.             call cmd(um, 'CountType "R"');l.r=umres
  406.             call cmd(um, 'CountType "F"');l.f=umres
  407.             call cmd(um, 'CountType "X"');l.x=umres
  408.             call cmd(um, 'CountType "U"');l.u=umres
  409.             pinfo=''
  410.             if tl.type='F' then pinfo='[Retrying failed] '
  411.             pinfo=pinfo||l.t' urls: 'l.q'Q, 'l.r'R'
  412.             if l.f~=0 then pinfo=pinfo', 'l.f'F'
  413.             if l.x~=0 then pinfo=pinfo', 'l.x'X'
  414.             if l.u~=0 then pinfo=pinfo', 'l.u'U'
  415.             call cmd(gh, 'SetProgressInfo "'pinfo'"')
  416.  
  417.             g.cnt = g.cnt+1
  418.             j = i+1
  419.  
  420.             if g.cnt > 1 then call Delay(opts.TDelay)
  421.         end
  422.         if i=0 then break
  423.  
  424.         gu.lmoved = 0
  425.         call GetUrl(i)
  426.         if gu.lmoved = 1 then do
  427.             call cmd(gh, 'GetHeaderString "Location:"')
  428.             if upper(left(ghres, 9)) = 'LOCATION:' then do
  429.                 newurl = strip(right(ghres, length(ghres)-10))
  430.                 call cmd(um, 'SetUrl ID 'i' URL "'newurl'"')
  431.                 drop newurl
  432.             end
  433.             else do
  434.                 gu.lmoved = 0
  435.             end
  436.         end
  437.         else do
  438.             if ((opts.MaxCount ~= 0 ) & (g.cnt >= opts.MaxCount)) then do
  439.                 call Log 'Received the maximal number of file allowed'
  440.                 return 0
  441.             end
  442.             tl.el = time('e')
  443.             if ((opts.MaxTime ~= 0) & (opts.MaxTimeS <= time('e'))) then do
  444.                 tl.el = tl.el/60
  445.                 call Log 'Downloaded 'tl.el' mins, max was 'opts.MaxTime' mins'
  446.                 return 0
  447.             end
  448.             call cmd(gh, 'GetByteRecd')
  449.             g.bytes = g.bytes + ghres
  450.             if (opts.MaxBytes ~= 0) & (g.bytes >= opts.MaxBytes) then do
  451.                 call Log 'Downloaded 'g.bytes' bytes, max was 'opts.MaxBytes' bytes'
  452.                 return 0
  453.             end
  454.         end
  455.     end
  456.  
  457. return 0
  458.  
  459. /** GetUrl *******************************************************************/
  460.  
  461. GetUrl:
  462.     PARSE ARG gu.id, gu.isfailed
  463.     
  464.     if cmd(um, 'GetURL 'gu.id) ~= 0 then return 0
  465.     gu.url = umres
  466.     if cmd(um, 'GetDepth 'gu.id) ~= 0 then return 0
  467.     gu.depth = umres
  468.     
  469.     gu.out = '['right(g.cnt, 4)'] 'gu.url
  470.     if gu.isfailed ~= '' then gu.out = gu.out' (F)'
  471.     if opts.Recursive then gu.out = gu.out' (D: 'gu.depth')'
  472.     
  473.     call Log(gu.out'...', 1)
  474.     
  475.     if upper(left(gu.url,7)) ~= "HTTP://" then do
  476.         call Log ' Not HTTP'
  477.         if def.KeepUnused then call cmd(um, 'SetType 'gu.id' U')
  478.         else call cmd(um, 'KillUrl 'hu.id)
  479.         if def.Secure then call SecureWorkFile
  480.         return 0
  481.     end
  482.     
  483.     /* Separate host & path */
  484.     parse var gu.url shit '://' gu.hp '/' gu.path
  485.  
  486.     if gu.hp = '' then do
  487.         call Log ' Not grabbed'
  488.         if def.KeepUnused then call cmd(um, 'SetType 'gu.id' U')
  489.         else call cmd(um, 'KillUrl 'hu.id)
  490.         if def.Secure then call SecureWorkFile
  491.         return 0
  492.     end
  493.     
  494.     /* Separate host & port */
  495.     parse var gu.hp gu.host ':' gu.port
  496.     
  497.     if gu.host = '' then do
  498.         call Log ' Not grabbed'
  499.         if def.KeepUnused then call cmd(um, 'SetType 'gu.id' U')
  500.         else call cmd(um, 'KillUrl 'hu.id)
  501.         if def.Secure then call SecureWorkFile
  502.         return 0
  503.     end
  504.     if gu.port = '' then gu.port = 80
  505.     
  506.     /* Complete the name */
  507.     if gu.path = '' then gu.path = 'index.html'
  508.     else if right(gu.path, 1) = '/' then gu.path = gu.path || 'index.html'
  509.     
  510.     /* Strip path if nodirs */
  511.     if opts.NoDirs then do while index(gu.path, '/') ~= 0
  512.         gu.path = right(gu.path, length(gu.path) - index(gu.path, '/'))
  513.     end
  514.     else gu.path = gu.host'/'gu.path
  515.  
  516.     /* Translates the filename */
  517.     if def.Translate ~= '' then do
  518.         call cmd(gh, 'Translate "'gu.path'" "'def.Translate'" "'def.TranslateTo'"')
  519.         gu.path = GHRES
  520.     end
  521.  
  522.     /* Check if it already exists */
  523.     if opts.NotExists & Exists(opts.SaveRoot||gu.path) then do
  524.         call Log ' Already on disk'
  525.         if def.KeepReceived then call cmd(um, 'SetType 'gu.id' R')
  526.         else call cmd(um, 'KillUrl 'hu.id)
  527.         if def.Secure then call SecureWorkFile
  528.         return 0
  529.     end
  530.  
  531.     thecmd = 'GetHTTPFile "'gu.url'"'
  532.     if def.Progress then thecmd = thecmd' Progress'
  533.     if ~opts.NoDirs then thecmd = thecmd' FileName "'gu.path'"'
  534.     if opts.MaxSize ~= 0 then thecmd = thecmd' MaxSize 'opts.MaxSize
  535.     if opts.SaveHeaders then thecmd = thecmd' SaveHeader'
  536.     if opts.IfModified then thecmd = thecmd' IfModified'
  537.     if opts.HeaderOnly then thecmd = thecmd' HeaderOnly'
  538.     if def.TouchOldDirs then thecmd = thecmd' TouchDirs'
  539.  
  540.     call cmd(gh, thecmd)
  541.     gu.res = ghres
  542.  
  543.     /* Authorization Check */
  544.     if gu.res = '100' then do
  545.         call cmd(gh, 'GetHeaderString "HTTP/1."')
  546.         parse var ghres dummy" "h.code" "h.msg
  547.         if h.code = '401' then do
  548.             call Log(' [Auth]', 1)
  549.             call cmd(gh, 'GetHeaderString "WWW-Authenticate: Basic "')
  550.             if RC=0 then do
  551.                 parse var ghres dummy '"'g.realm'"'
  552.                 g.authpwd = GetRealm(g.realm)
  553.                 if g.authpwd = '' then do
  554.                     call Log(' Unknown realm: "'g.realm'"', 1)
  555.                     gu.res = 9999
  556.                 end
  557.                 else do
  558.                     call cmd(gh, 'SetAuth "'g.authpwd'"')
  559.                     if RC~=0 then call DoFail(20, "Error: can't alloc mem for authentication!")
  560.                     call cmd(gh, thecmd)
  561.                     gu.res = ghres
  562.                     call cmd(gh, 'SetAuth')
  563.                 end
  564.             end
  565.             else do
  566.                 call Log(' Unknown authentication method!')
  567.                 gh.res = 9999
  568.             end
  569.         end
  570.     end
  571.  
  572.     if gu.res = '0' then do
  573.         if def.KeepReceived then call cmd(um, 'SetType 'gu.id' R')
  574.         else call cmd(um, 'KillUrl 'hu.id)
  575.         call Log(' Done.', 1)
  576.         end
  577.     else if gu.res = '200' then do
  578.         call cmd(um, 'SetType 'gu.id' F')
  579.         call Log(' Incomplete file.', 1)
  580.     end
  581.     else if gu.res = '9999' then nop
  582.     else if gu.res = '100' then do
  583.         call cmd(gh, 'GetHeaderString "HTTP/1."')
  584.         parse var ghres dummy" "h.code" "h.msg
  585.         if h.code = '304' then do
  586.             call Log(' Not modified.', 1)
  587.             if def.KeepReceived then call cmd(um, 'SetType 'gu.id' R')
  588.             else call cmd(um, 'KillUrl 'hu.id)
  589.             end
  590.         else if h.code = '301' then do
  591.             call Log(' Moved.', 1)
  592.             if def.FollowMoved = '1' then gu.lmoved = 1
  593.             else if def.FollowMoved = 'F' then call cmd(um, 'SetType 'gu.id' F')
  594.             else if def.FollowMoved = 'X' then call cmd(um, 'SetType 'gu.id' X')
  595.             end
  596.         else if h.code = '302' then do
  597.             call Log(' Moved temporarily.', 1)
  598. /*            if def.KeepReceived then call cmd(um, 'SetType 'gu.id' F') */
  599. /*            else call cmd(um, 'KillUrl 'hu.id) */
  600.             if def.FollowTMoved = '1' then gu.lmoved = 1
  601.             else if def.FollowTMoved = 'F' then call cmd(um, 'SetType 'gu.id' F')
  602.             else if def.FollowTMoved = 'X' then call cmd(um, 'SetType 'gu.id' X')
  603.             end
  604.         else if h.code = '401' then do
  605.             call Log(' Bad user/password.', 1)
  606.             call cmd(um, 'SetType 'gu.id' U')
  607.             end
  608.         else do
  609.             call Log(' 'h.code' 'h.msg'.', 1)
  610.             if def.KeepReceived then call cmd(um, 'SetType 'gu.id' X')
  611.             else call cmd(um, 'KillUrl 'hu.id)
  612.             end
  613.         end
  614.     else if gu.res='104' then do
  615.         call Log(' Host not found.', 1)
  616.         call cmd(um, 'SetType 'gu.id' X')
  617.     end
  618.     else if gu.res='107' then do
  619.         call Log(' Disk Full.', 1)
  620.         call DoFail(20, "Error Disk Full.")
  621.     end
  622.     else if gu.res='200' then do
  623.         call Log(' File incomplete.', 1)
  624.         call cmd(um, 'SetType 'gu.id' F')
  625.     end
  626.     else if gu.res='201' then do
  627.         call Log(' Stopped by user.', 1)
  628.         call cmd(um, 'SetType 'gu.id' F')
  629.     end
  630.     else if gu.res='202' then do
  631.         call Log(' Aborted by user.')
  632.         call DoFail(10, "Error: User abort.")
  633.     end
  634.     else if gu.res='97' then do
  635.         call Log(' Failed to create socket.', 1)
  636.         call DoFail(20, "Error.")
  637.     end
  638.     else if (gu.res='98') | (gu.res='99') | (gu.res='164') then do
  639.         call Log(' Not enough memory.', 1)
  640.         call DoFail(20, "Error.")
  641.     end
  642.     else do
  643.         call Log(' Failed code 'gu.res'.', 1)
  644.         if def.KeepFailed then call cmd(um, 'SetType 'gu.id' F')
  645.         else call cmd(um, 'KillUrl 'hu.id)
  646.     end
  647.  
  648.     if gu.res == '0' & opts.Recursive then do
  649.         call cmd(gh, 'GetHeaderString "Content-Type:"')
  650.         if (index(upper(ghres), 'TEXT/HTML')~=0) | (index(upper(gu.path), '.HTM') > (length(gu.path)-5)) then do
  651.             if gu.depth ~= 0 then do
  652.                 if gu.depth = -1 then gu.newdepth = -1
  653.                 else gu.newdepth = gu.depth - 1
  654.  
  655.                 thecmd = def.ScanHTML' "'opts.SaveRoot||gu.path'" "'def.TempFile'"'
  656.                 thecmd = thecmd' Base "'gu.url'" Pattern2 "'def.ParsePattern'" Strip# NoF# NoQuery'
  657.                 if opts.Pattern ~= '' then thecmd = thecmd' Pattern "'opts.Pattern'"'
  658.                 if opts.NoSrc then thecmd = thecmd' NoSrc'
  659.                 if opts.NoHRef then thecmd = thecmd' NoHRef'
  660.                 if opts.NoBG then thecmd = thecmd' NoBG'
  661.  
  662.                 address command thecmd
  663.                 if RC ~= 0 then call Log ' (Can''t parse)'
  664.                 else do
  665.                     if cmd(um, 'ReadFile 'def.TempFile' Q Depth 'gu.newdepth) ~= 0 then do
  666.                         call Log ' (Can''t add urls)'
  667.                     end
  668.                     else do
  669.                         if umres = '0' then call Log ''
  670.                         else if umres = '1' then
  671.                             call Log ' (+1 url)'
  672.                         else call Log ' (+'umres' urls)'
  673.                     end
  674.                 end
  675.                 call Delete(def.TempFile)
  676.             end
  677.             else call Log
  678.         end
  679.         else call Log
  680.     end
  681.     else call Log ''
  682.  
  683.     call SecureWorkFile
  684.  
  685. return 0
  686.  
  687. novalue:
  688.     call oops("Novalue", sigl)
  689. syntax:
  690.     call oops("Syntax(RC="RC")", sigl, RC)
  691. failure:
  692.     call oops("Failure(RC="RC")", sigl)
  693. ioerr:
  694.     call oops("IOErr", sigl)
  695. halt:
  696.     call oops("Halt", sigl)
  697. error:
  698.     call oops("Error", sigl)
  699. oops:
  700.     parse arg what, badline, code
  701.     if code != '' then
  702.         call DoFail(40, "ERR: Line "badline what errortext(code))
  703.     else
  704.         call DoFail(40, "ERR: Line "badline what)
  705.